/*
 * TowerRedTwo.java
 *
 * Created on December 19, 2007, 8:43 PM
 *
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package hextd.tower;

import hextd.Constants;
import hextd.hex.HexTile;
import hextd.creep.HexTDCreep;
import hextd.util.Cache;
import hextd.util.Geometry;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @author hylke
 */
public class TowerRedTwo extends TowerBase {

	public static final Map<String, Long> price = new HashMap<String, Long>();

	static {
		price.put(Constants.RESOURCE_CREDIT, 20000l);
	}
	public static int damage = 20000;
	public static double range = 6f;
	public static double spreadRadiusBase = 2f;
	public static double projectileSpeedBase = 0.4f;
	public static String name = "Red Two";
	//
	private HexTDCreep fireAt = null;
	private Constants.COLOR damageColor = Constants.COLOR.RED;
	private int coolDown = 0;
	private int coolDownTime = 14;
	private Color transColor;
	private double projectileSpeed;
	private double spreadRadius;
	private double spreadRadius2;
	private List<Projectile> projectiles;
	private BufferedImage[] projectileImg;
	private Point2D.Double tempTargetGLoc = new Point2D.Double();
	private Point2D.Double tempTargetPLoc = new Point2D.Double();

	/** Creates a new instance of TowerRedTwo */
	public TowerRedTwo() {
		super(FactoryTower.type.redTwo, price, damage, range);
		lineColor = Color.RED;
		transColor = new Color(lineColor.getRed(), lineColor.getGreen(), lineColor.getBlue(), 50);
		projectiles = new ArrayList<Projectile>();
	}

	@Override
	public void runTick(int gameTime) {
		if (coolDown > 0) {
			coolDown--;
		} else {
			if (!lock) {
				fireAt = null;
			}
			HexTDCreep enemy = findEnemy(fireAt, false);
			fireAt = enemy;

			if (enemy != null) {
				Projectile p = new Projectile();
				p.target = enemy;
				p.x = gameLocation.x;
				p.y = gameLocation.y;
				projectiles.add(p);
				coolDown = coolDownTime;
			}
		}

		for (int ip = projectiles.size() - 1; ip >= 0; ip--) {
			Projectile p = projectiles.get(ip);
			double dx, dy, r, factor;
			p.target.getGameLocation(tempTargetGLoc);
			if (p.status == 0) {
				dx = tempTargetGLoc.x - p.x;
				dy = tempTargetGLoc.y - p.y;
				r = (double) Math.sqrt(dx * dx + dy * dy);
				factor = projectileSpeed / r;
				if (factor < 1) {
					dx *= factor;
					dy *= factor;
					p.x += dx;
					p.y += dy;
				} else {
					// HIT!
					p.x = tempTargetGLoc.x;
					p.y = tempTargetGLoc.y;
					p.status = 1;
				}
			}
			if (p.status == 1) {
				p.targetsHit = findEnemiesInRange(p.x, p.y, spreadRadius);
				long damageBlast;
				double rs;
				HexTDCreep enemy;
				for (int i = 0; i < p.targetsHit.length; i++) {
					enemy = p.targetsHit[i];
					enemy.getGameLocation(tempTargetGLoc);
					dx = p.x - tempTargetGLoc.x;
					dy = p.y - tempTargetGLoc.y;
					rs = (double) Math.sqrt(dx * dx + dy * dy);
					damageBlast = Math.round(damageCurrent * (1 - rs / spreadRadius));
					enemy.doDamage(getOwner(), damageBlast, damageColor);
				}
				p.status++;
			} else if (p.status > 1) {
				p.target = null;
				projectiles.remove(ip);
			}
		}
	}

	@Override
	public String getStatusString() {
		String retString = "";
		retString += "<h1>Red Tower 2</h1>"
				+ "<p>"
				+ "<b>Level:</b> " + (1 + level) + "<br>\n"
				+ "<b>Damage:</b> " + damageText + "<br>\n"
				+ "<b>Range:</b> " + rangeText + "<br>"
				+ "</p>\n";
		return retString;
	}

	@Override
	public String getDescription() {
		String retString = "";
		retString += "<h1>Red Tower 2</h1>"
				+ "<p>"
				+ "Tower firing fast homing projectiles with a small splash radius. "
				+ "When the projectiles lose their target they continue to the last known location and detonate."
				+ "<br>Strong against red enemies, very weak against green enemies."
				+ "</p>"
				+ "<p>"
				+ "<b>Price:</b> " + TowerRedTwo.form.format(TowerRedTwo.price) + "<br>"
				+ "<b>Damage:</b> " + TowerRedTwo.form.format(damageCurrent) + " + splash<br>"
				+ "<b>Range:</b> " + TowerRedTwo.form.format(rangeCurrent) + "<br>"
				+ "<b>Refire rate:</b> 1.25/s"
				+ "</p>";
		return retString;
	}

	@Override
	protected void calcDamageRange() {
		super.calcDamageRange();
		spreadRadius = TowerRedTwo.spreadRadiusBase;
		spreadRadius2 = spreadRadius * spreadRadius;
		projectileSpeed = projectileSpeedBase;
	}

	@Override
	protected void generateShapes() {
		Cache cache = Cache.getInstance();

		double width = HexTile.relativeHexWidth;
		int shapeCount = 5;
		shapes = new Shape[shapeCount];
		shapes[0] = new Ellipse2D.Double(-0.3 * paintScale, -0.3 * paintScale, 0.6 * paintScale, 0.6 * paintScale);
		shapes[1] = new Ellipse2D.Double(-0.3 * paintScale, -0.3 * paintScale, 0.6 * paintScale, 0.6 * paintScale);
		shapes[2] = new Ellipse2D.Double(-1.0 * strokeScale, -1.0 * strokeScale, 2.0 * strokeScale, 2.0 * strokeScale);
		shapes[3] = new Line2D.Double(width, 0.5 * paintScale, 0.3 * width, 0.15 * paintScale);
		shapes[4] = new Line2D.Double(-width, -0.5 * paintScale, -0.3 * width, -0.15 * paintScale);

		shapeAction = new int[shapeCount];
		shapeAction[0] = 2;
		shapeAction[1] = 1;
		shapeAction[2] = 1;
		shapeAction[3] = 1;
		shapeAction[4] = 1;

		shapeColor = new Color[shapeCount];
		shapeColor[0] = transColor;
		shapeColor[1] = lineColor;
		shapeColor[2] = lineColor;
		shapeColor[3] = lineColor;
		shapeColor[4] = lineColor;

		strokes = new Stroke[shapeCount];
		strokes[0] = new BasicStroke(2.0f * strokeScale, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
		strokes[1] = strokes[0];
		strokes[2] = strokes[0];
		strokes[3] = strokes[0];
		strokes[4] = strokes[0];

		if (cache.hasBufImgArr("Red2ProjImagArr")) {
			projectileImg = cache.getBufImgArr("Red2ProjImagArr");
		} else {
			double pWidth = width / 10f;
			double pScale = paintScale / 10f;
			int imgW = (int) (pScale * 2) + 2;
			int imgH = (int) (pScale * 2) + 2;
			projectileImg = new BufferedImage[3];
			double[][] pPoints = Geometry.createHexCoords(pScale, (double) imgW / 2, (double) imgH / 2);
			AffineTransform atr = new AffineTransform();
			for (int i = 0; i < projectileImg.length; i++) {
				atr.setToIdentity();
				atr.rotate(Math.PI * i * 2 / 6 / 3, (double) imgW / 2, (double) imgH / 2);

				projectileImg[i] = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB_PRE);
				//GeneralPath polyHex = Geometry.coordsToGeneralPath(pPoints, true);
				Graphics2D g2 = projectileImg[i].createGraphics();
				g2.transform(atr);
				g2.setColor(lineColor);
				//g2.draw(polyHex);
				g2.draw(new Line2D.Double(pPoints[0][0], pPoints[0][1], pPoints[3][0], pPoints[3][1]));
				g2.draw(new Line2D.Double(pPoints[1][0], pPoints[1][1], pPoints[4][0], pPoints[4][1]));
				g2.draw(new Line2D.Double(pPoints[2][0], pPoints[2][1], pPoints[5][0], pPoints[5][1]));
				g2.dispose();
			}
			cache.putBufImgArr("Red2ProjImagArr", projectileImg);
		}

	}

	@Override
	public void paintEffects(Graphics2D g2, int gameTime) {
		Stroke defaultStroke = g2.getStroke();

		g2.setColor(lineColor);

		double pw = (double) projectileImg[0].getWidth() / 2f;
		double ph = (double) projectileImg[0].getHeight() / 2f;
		for (int ip = 0; ip < projectiles.size(); ip++) {
			Projectile p = projectiles.get(ip);
			if (p.status == 0) {
				g2.drawImage(
						projectileImg[p.anim],
						(int) Math.round(p.x * paintScale + offsetX - pw),
						(int) Math.round(p.y * paintScale + offsetY - ph),
						null);
				p.anim++;
				if (p.anim >= projectileImg.length) {
					p.anim = 0;
				}
			} else {
				HexTDCreep[] targetsHit = p.targetsHit;
				if (targetsHit != null) {
					for (int i = 0; i < targetsHit.length; i++) {
						targetsHit[i].getPaintLocation(tempTargetPLoc);
						g2.draw(new Line2D.Double(
								p.x * paintScale + offsetX,
								p.y * paintScale + offsetY,
								tempTargetPLoc.x,
								tempTargetPLoc.y));
					}
				}
			}
		}

		g2.setStroke(defaultStroke);
	}
}
